package com.imut.lagain.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.util.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * 加密工具类
 */
public class EncryptUtil {
    private static final Logger log = LoggerFactory.getLogger(EncryptUtil.class);
    private static final String AES_ALGORITHM = "AES";
    private static final String AES_TRANSFORMATION = "AES/ECB/PKCS5Padding";
    private static final String DEFAULT_SECRET_KEY = "LAgainSecretKey2024";
    
    /**
     * MD5加密
     * @param input 输入字符串
     * @return MD5加密后的字符串
     */
    public static String md5(String input) {
        if (!StringUtils.hasText(input)) {
            return null;
        }
        
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(digest);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5加密失败", e);
        }
    }
    
    /**
     * SHA-256加密
     * @param input 输入字符串
     * @return SHA-256加密后的字符串
     */
    public static String sha256(String input) {
        if (!StringUtils.hasText(input)) {
            return null;
        }
        
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(digest);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("SHA-256加密失败", e);
        }
    }
    
    /**
     * SHA-512加密
     * @param input 输入字符串
     * @return SHA-512加密后的字符串
     */
    public static String sha512(String input) {
        if (!StringUtils.hasText(input)) {
            return null;
        }
        
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-512");
            byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(digest);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("SHA-512加密失败", e);
        }
    }
    
    /**
     * AES加密（使用默认密钥）
     * @param plainText 明文
     * @return 加密后的Base64字符串
     */
    public static String aesEncrypt(String plainText) {
        return aesEncrypt(plainText, DEFAULT_SECRET_KEY);
    }
    
    /**
     * AES加密
     * @param plainText 明文
     * @param secretKey 密钥
     * @return 加密后的Base64字符串
     */
    public static String aesEncrypt(String plainText, String secretKey) {
        if (!StringUtils.hasText(plainText) || !StringUtils.hasText(secretKey)) {
            return null;
        }
        
        try {
            SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), AES_ALGORITHM);
            Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec);
            
            byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            throw new RuntimeException("AES加密失败", e);
        }
    }
    
    /**
     * AES解密（使用默认密钥）
     * @param encryptedText 加密的Base64字符串
     * @return 解密后的明文
     */
    public static String aesDecrypt(String encryptedText) {
        return aesDecrypt(encryptedText, DEFAULT_SECRET_KEY);
    }
    
    /**
     * AES解密
     * @param encryptedText 加密的Base64字符串
     * @param secretKey 密钥
     * @return 解密后的明文
     */
    public static String aesDecrypt(String encryptedText, String secretKey) {
        if (!StringUtils.hasText(encryptedText) || !StringUtils.hasText(secretKey)) {
            return null;
        }
        
        try {
            SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), AES_ALGORITHM);
            Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, keySpec);
            
            byte[] encrypted = Base64.getDecoder().decode(encryptedText);
            byte[] decrypted = cipher.doFinal(encrypted);
            return new String(decrypted, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("AES解密失败", e);
        }
    }
    
    /**
     * 生成AES密钥
     * @return Base64编码的密钥
     */
    public static String generateAESKey() {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(AES_ALGORITHM);
            keyGenerator.init(256);
            SecretKey secretKey = keyGenerator.generateKey();
            return Base64.getEncoder().encodeToString(secretKey.getEncoded());
        } catch (Exception e) {
            throw new RuntimeException("生成AES密钥失败", e);
        }
    }
    
    /**
     * Base64编码
     * @param input 输入字符串
     * @return Base64编码后的字符串
     */
    public static String base64Encode(String input) {
        if (!StringUtils.hasText(input)) {
            return null;
        }
        return Base64.getEncoder().encodeToString(input.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * Base64解码
     * @param input Base64编码的字符串
     * @return 解码后的字符串
     */
    public static String base64Decode(String input) {
        if (!StringUtils.hasText(input)) {
            return null;
        }
        try {
            byte[] decoded = Base64.getDecoder().decode(input);
            return new String(decoded, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("Base64解码失败", e);
        }
    }
    
    /**
     * 生成随机盐值
     * @param length 盐值长度
     * @return 随机盐值
     */
    public static String generateSalt(int length) {
        if (length <= 0) {
            length = 16;
        }
        
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[length];
        random.nextBytes(salt);
        return bytesToHex(salt);
    }
    
    /**
     * 生成随机盐值（默认16位）
     * @return 随机盐值
     */
    public static String generateSalt() {
        return generateSalt(16);
    }
    
    /**
     * 带盐值的MD5加密
     * @param input 输入字符串
     * @param salt 盐值
     * @return 加密后的字符串
     */
    public static String md5WithSalt(String input, String salt) {
        if (!StringUtils.hasText(input)) {
            return null;
        }
        
        String saltedInput = input + (salt != null ? salt : "");
        return md5(saltedInput);
    }
    
    /**
     * 带盐值的SHA-256加密
     * @param input 输入字符串
     * @param salt 盐值
     * @return 加密后的字符串
     */
    public static String sha256WithSalt(String input, String salt) {
        if (!StringUtils.hasText(input)) {
            return null;
        }
        
        String saltedInput = input + (salt != null ? salt : "");
        return sha256(saltedInput);
    }
    
    /**
     * 验证MD5哈希值
     * @param input 原始输入
     * @param hash 哈希值
     * @return 是否匹配
     */
    public static boolean verifyMd5(String input, String hash) {
        if (!StringUtils.hasText(input) || !StringUtils.hasText(hash)) {
            return false;
        }
        return hash.equals(md5(input));
    }
    
    /**
     * 验证SHA-256哈希值
     * @param input 原始输入
     * @param hash 哈希值
     * @return 是否匹配
     */
    public static boolean verifySha256(String input, String hash) {
        if (!StringUtils.hasText(input) || !StringUtils.hasText(hash)) {
            return false;
        }
        return hash.equals(sha256(input));
    }
    
    /**
     * 验证带盐值的MD5哈希值
     * @param input 原始输入
     * @param salt 盐值
     * @param hash 哈希值
     * @return 是否匹配
     */
    public static boolean verifyMd5WithSalt(String input, String salt, String hash) {
        if (!StringUtils.hasText(input) || !StringUtils.hasText(hash)) {
            return false;
        }
        return hash.equals(md5WithSalt(input, salt));
    }
    
    /**
     * 验证带盐值的SHA-256哈希值
     * @param input 原始输入
     * @param salt 盐值
     * @param hash 哈希值
     * @return 是否匹配
     */
    public static boolean verifySha256WithSalt(String input, String salt, String hash) {
        if (!StringUtils.hasText(input) || !StringUtils.hasText(hash)) {
            return false;
        }
        return hash.equals(sha256WithSalt(input, salt));
    }
    
    /**
     * 字节数组转十六进制字符串
     * @param bytes 字节数组
     * @return 十六进制字符串
     */
    private static String bytesToHex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(String.format("%02x", b));
        }
        return result.toString();
    }
    
    /**
     * 十六进制字符串转字节数组
     * @param hex 十六进制字符串
     * @return 字节数组
     */
    public static byte[] hexToBytes(String hex) {
        if (!StringUtils.hasText(hex) || hex.length() % 2 != 0) {
            throw new IllegalArgumentException("无效的十六进制字符串");
        }
        
        byte[] bytes = new byte[hex.length() / 2];
        for (int i = 0; i < hex.length(); i += 2) {
            bytes[i / 2] = (byte) Integer.parseInt(hex.substring(i, i + 2), 16);
        }
        return bytes;
    }
    
    /**
     * 生成随机字符串
     * @param length 长度
     * @return 随机字符串
     */
    public static String generateRandomString(int length) {
        if (length <= 0) {
            return "";
        }
        
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        SecureRandom random = new SecureRandom();
        StringBuilder sb = new StringBuilder(length);
        
        for (int i = 0; i < length; i++) {
            sb.append(chars.charAt(random.nextInt(chars.length())));
        }
        
        return sb.toString();
    }
    
    /**
     * 生成随机数字字符串
     * @param length 长度
     * @return 随机数字字符串
     */
    public static String generateRandomNumber(int length) {
        if (length <= 0) {
            return "";
        }
        
        SecureRandom random = new SecureRandom();
        StringBuilder sb = new StringBuilder(length);
        
        for (int i = 0; i < length; i++) {
            sb.append(random.nextInt(10));
        }
        
        return sb.toString();
    }
    
    /**
     * 私有构造函数，防止实例化
     */
    private EncryptUtil() {
    }
}
